#include <iostream>
#include <pthread.h>
#include <vector>
#include <string>
#include <unistd.h>
#include <memory>
#include "Thread.hpp"
#include "Mutex.hpp"

int tickets = 10000;
// 为了出现我们想要的问题
// 就需要尽可能的让多个线程交叉执行
// 多个线程交叉执行本质：就是让调度器尽可能的频繁发生线程调度与切换
// 线程一般在什么时候发生切换呢？时间片到了，来了更高优先级的线程，线程等待的时候。
// 线程是在什么时候检测上面的问题呢？从内核态返回用户态的时候，线程要对调度状态进行检测，如果可以，就直接发生线程切换

// pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

class ThreadData
{
public:
    ThreadData(const std::string threadname, pthread_mutex_t *mutex)
        : threadname_(threadname), mutex_p_(mutex)
    {
    }
    ~ThreadData()
    {
    }

public:
    std::string threadname_;
    pthread_mutex_t *mutex_p_;
};

void *get_tickets(void *args)
{
    // std::string username = static_cast<const char *>(args);
    ThreadData *td = static_cast<ThreadData *>(args);
    while (true)
    {
        // pthread_mutex_lock(td->mutex_p_);
        LockGuard lockguard(td->mutex_p_);
        {
            if (tickets > 0)
            {
                usleep(1234); // 模拟真实抢票花费时间
                std::cout << td->threadname_ << "正在抢票：" << tickets << std::endl;
                tickets--;
                //pthread_mutex_unlock(td->mutex_p_);
            }
            else
            {
                //pthread_mutex_unlock(td->mutex_p_);
                break;
            }
        }
        // 抢票完了还有其他工作
        usleep(1000); // 线程生成订单
    }
    return nullptr;
}

int main()
{
#define NUM 4
    pthread_mutex_t lock;
    pthread_mutex_init(&lock, nullptr);

    std::vector<pthread_t> tids(NUM);

    for (int i = 0; i < NUM; i++)
    {
        char buffer[64];
        snprintf(buffer, sizeof buffer, "thread %d", i + 1);
        ThreadData *td = new ThreadData(buffer, &lock);
        pthread_create(&tids[i], nullptr, get_tickets, td);
    }

    for (const auto &tid : tids)
    {
        pthread_join(tid, nullptr);
    }

    // pthread_t t1,t2,t3,t4;
    // pthread_create(&t1,nullptr,get_tickets,(void*)"thread 1");
    // pthread_create(&t1,nullptr,get_tickets,(void*)"thread 2");
    // pthread_create(&t1,nullptr,get_tickets,(void*)"thread 3");
    // pthread_create(&t1,nullptr,get_tickets,(void*)"thread 4");

    // pthread_join(t1,nullptr);
    // pthread_join(t2,nullptr);
    // pthread_join(t3,nullptr);
    // pthread_join(t4,nullptr);

    pthread_mutex_destroy(&lock);

    // std::unique_ptr<Thread> thread1(new Thread(get_tickets, (void *)"user1", 1));
    // std::unique_ptr<Thread> thread2(new Thread(get_tickets, (void *)"user2", 2));
    // std::unique_ptr<Thread> thread3(new Thread(get_tickets, (void *)"user3", 3));
    // std::unique_ptr<Thread> thread4(new Thread(get_tickets, (void *)"user4", 4));
    // thread1->join();
    // thread2->join();
    // thread3->join();
    // thread4->join();
    return 0;
}